// Student Name: jiawei lyu
// Date: 2.10.2024

#include "doubly_linked_list.h"
#include <iostream>

DoublyLinkedList::DoublyLinkedList() : head(nullptr), tail(nullptr) {}

DoublyLinkedList::~DoublyLinkedList() {
    clear();
}

bool DoublyLinkedList::isEmpty() {
    return head == nullptr;
}

void DoublyLinkedList::insertAtHead(int key) {
    DllNode* newNode = new DllNode(key);
    if (isEmpty()) {
        head = tail = newNode;
    } else {
        newNode->next = head;
        head->prev = newNode;
        head = newNode;
    }
}

void DoublyLinkedList::insertAtTail(int key) {
    DllNode* newNode = new DllNode(key);
    if (isEmpty()) {
        head = tail = newNode;
    } else {
        tail->next = newNode;
        newNode->prev = tail;
        tail = newNode;
    }
}

void DoublyLinkedList::remove(int key) {
    DllNode* current = head;
    while (current != nullptr) {
        if (current->key == key) {
            if (current == head) {
                removeHeaderNode();
            } else if (current == tail) {
                removeTailNode();
            } else {
                current->prev->next = current->next;
                current->next->prev = current->prev;
                delete current;
            }
            return;
        }
        current = current->next;
    }
}

void DoublyLinkedList::removeHeaderNode() {
    if (isEmpty()) return;
    DllNode* temp = head;
    head = head->next;
    if (head != nullptr) {
        head->prev = nullptr;
    } else {
        tail = nullptr;
    }
    delete temp;
}

void DoublyLinkedList::removeTailNode() {
    if (isEmpty()) return;
    DllNode* temp = tail;
    tail = tail->prev;
    if (tail != nullptr) {
        tail->next = nullptr;
    } else {
        head = nullptr;
    }
    delete temp;
}

void DoublyLinkedList::moveNodeToHead(int key) {
    DllNode* current = head;
    while (current != nullptr) {
        if (current->key == key) {
            if (current == head) return;
            if (current == tail) {
                tail = tail->prev;
                tail->next = nullptr;
            } else {
                current->prev->next = current->next;
                current->next->prev = current->prev;
            }
            current->next = head;
            head->prev = current;
            head = current;
            head->prev = nullptr;
            return;
        }
        current = current->next;
    }
}

void DoublyLinkedList::moveNodeToTail(int key) {
    DllNode* current = head;
    while (current != nullptr) {
        if (current->key == key) {
            if (current == tail) return;
            if (current == head) {
                head = head->next;
                head->prev = nullptr;
            } else {
                current->prev->next = current->next;
                current->next->prev = current->prev;
            }
            current->prev = tail;
            tail->next = current;
            tail = current;
            tail->next = nullptr;
            return;
        }
        current = current->next;
    }
}

void DoublyLinkedList::clear() {
    while (!isEmpty()) {
        removeHeaderNode();
    }
}
